package com.zg.indiv.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zg.common.core.dao.auth.AuthUser;
import com.zg.common.core.dao.auth.AuthUserDao;
import com.zg.common.core.dao.indiv.IndivFolderDao;
import com.zg.common.core.dao.indiv.IndivSpaceDao;
import com.zg.common.core.dao.indiv.IndivSpaceUserDao;
import com.zg.common.core.dao.indiv.entity.IndivFolder;
import com.zg.common.core.dao.indiv.entity.IndivSpace;
import com.zg.common.core.dao.indiv.entity.IndivSpaceUser;
import com.zg.common.core.exception.BusinessException;
import com.zg.indiv.constants.IndivConstant;
import com.zg.indiv.constants.IndivExceptionEnum;
import com.zg.indiv.domain.req.space.*;
import com.zg.indiv.domain.vo.IndivSpaceCountFileVo;
import com.zg.indiv.domain.vo.IndivSpaceCountRecordVo;
import com.zg.indiv.service.IndivSpaceService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
* @author lixin
*/
@Service
@RequiredArgsConstructor
public class IndivSpaceServiceImpl implements IndivSpaceService {

    private final IndivSpaceDao indivSpaceDao;
    private final IndivSpaceUserDao indivSpaceUserDao;
    private final AuthUserDao authUserDao;
    private final IndivFolderDao indivFolderDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(IndivSpaceAddReq param) {
        Integer dataType = param.getDataType();
        if (IndivConstant.INDIV_DATA_TYPE_FORM.equals(dataType)) {
            if (param.getFormId() == null) {
                BusinessException.happen("请选择正确的表单");
            }
            param.setFileType(null);
            param.setFileMaxSize(null);
        } else if (IndivConstant.INDIV_DATA_TYPE_FILE.equals(dataType)) {
            if (StrUtil.isBlank(param.getFileType())) {
                BusinessException.happen("请选择正确的文件类型");
            }
            if (param.getFileMaxSize() == null || param.getFileMaxSize() < 0) {
                BusinessException.happen("请选择正确的文件最大限制");
            }
            param.setFormId(null);
        }
        String[] names = param.getName().split(",");
        List<IndivSpace> list = new ArrayList<>();
        Map<String, String> nameMap = new HashMap<>();
        for (String name : names) {
            if (nameMap.containsKey(name)) {
                BusinessException.happen("空间名称已被使用");
            }
            nameMap.put(name, name);
            IndivSpace indivSpace = BeanUtil.copyProperties(param, IndivSpace.class);
            indivSpace.setName(name);
            list.add(indivSpace);
        }
        indivSpaceDao.saveBatch(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(IndivSpaceEditReq param) {
        IndivSpace oldIndivSpace = indivSpaceDao.getById(param.getSpaceId());
        if (oldIndivSpace == null) {
            BusinessException.happen(IndivExceptionEnum.SPACE_NO.getCode(),
                    IndivExceptionEnum.SPACE_NO.getMsg());
        }
        if (!oldIndivSpace.getName().equals(param.getName())) {
            long nameCount = indivSpaceDao.count(
                    new LambdaQueryWrapper<IndivSpace>()
                            .eq(IndivSpace::getName, param.getName())
            );
            if (nameCount > 0) {
                BusinessException.happen(IndivExceptionEnum.SPACE_NAME_ERROR.getCode(),
                        IndivExceptionEnum.SPACE_NAME_ERROR.getMsg());
            }
        }
        Integer dataType = param.getDataType();
        if (IndivConstant.INDIV_DATA_TYPE_FORM.equals(dataType)) {
            if (param.getFormId() == null) {
                BusinessException.happen("请选择正确的表单");
            }
            param.setFileType(null);
            param.setFileMaxSize(null);
        } else if (IndivConstant.INDIV_DATA_TYPE_FILE.equals(dataType)) {
            if (StrUtil.isBlank(param.getFileType())) {
                BusinessException.happen("请选择正确的文件类型");
            }
            if (param.getFileMaxSize() == null || param.getFileMaxSize() < 0) {
                BusinessException.happen("请选择正确的文件最大限制");
            }
            param.setFormId(null);
        }
        IndivSpace indivSpace = BeanUtil.copyProperties(param, IndivSpace.class);
        indivSpace.setId(param.getSpaceId());
        indivSpaceDao.updateById(indivSpace);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addUser(IndivSpaceAddUserReq param) {
        IndivSpace indivSpace = indivSpaceDao.getById(param.getSpaceId());
        if (indivSpace == null) {
            BusinessException.happen(IndivExceptionEnum.SPACE_NO.getCode(),
                    IndivExceptionEnum.SPACE_NO.getMsg());
        }

        List<IndivSpaceUser> indivSpaceUsers = indivSpaceUserDao.list(
                new LambdaQueryWrapper<IndivSpaceUser>()
                        .eq(IndivSpaceUser::getSpaceId, param.getSpaceId())
        );
        Set<Long> userIdSet = indivSpaceUsers.stream().map(IndivSpaceUser::getUserId).collect(Collectors.toSet());

        List<AuthUser> authUsers = authUserDao.listByIds(param.getUserIds());
        List<IndivSpaceUser> addList = new ArrayList<>();
        for (AuthUser authUser : authUsers) {
            Long userId = authUser.getId();
            if (userIdSet.contains(userId)) {
                userIdSet.remove(userId);
                continue;
            }
            IndivSpaceUser indivSpaceUser = new IndivSpaceUser();
            indivSpaceUser.setSpaceId(param.getSpaceId());
            indivSpaceUser.setUserId(authUser.getId());
            addList.add(indivSpaceUser);
        }
        if (addList.size() > 0) {
            indivSpaceUserDao.saveBatch(addList);
        }
        if (!userIdSet.isEmpty()) {
            indivSpaceUserDao.remove(
                    new LambdaQueryWrapper<IndivSpaceUser>()
                            .eq(IndivSpaceUser::getSpaceId, param.getSpaceId())
                            .in(IndivSpaceUser::getUserId, userIdSet)
            );
        }
    }

    @Override
    public List<IndivSpaceUser> listUser(IndivSpaceListUserReq param) {
        IndivSpace indivSpace = indivSpaceDao.getById(param.getSpaceId());
        if (indivSpace == null) {
            BusinessException.happen(IndivExceptionEnum.SPACE_NO.getCode(),
                    IndivExceptionEnum.SPACE_NO.getMsg());
        }

        List<IndivSpaceUser> list = indivSpaceUserDao.list(
                new QueryWrapper<IndivSpaceUser>()
                        .lambda()
                        .eq(IndivSpaceUser::getSpaceId, param)
        );
        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeUser(List<Long> idList) {
        indivSpaceUserDao.removeByIds(idList);
    }

    @Override
    public IPage<IndivSpace> page(IndivSpacePageReq param) {
        LambdaQueryWrapper<IndivSpace> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        String searchStr = param.getSearchStr();
        lambdaQueryWrapper.like(StrUtil.isNotBlank(searchStr), IndivSpace::getSearchStr, "%" + searchStr + "%");
        lambdaQueryWrapper.orderByDesc(IndivSpace::getUpdateTime);
        return indivSpaceDao.page(
                new Page<>(param.getPage(), param.getPageSize()),
                lambdaQueryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editCapacity(IndivSpaceEditCapacityReq param) {
        IndivSpace indivSpace = indivSpaceDao.getById(param.getSpaceId());
        if (indivSpace == null) {
            BusinessException.happen(IndivExceptionEnum.SPACE_NO.getCode(),
                    IndivExceptionEnum.SPACE_NO.getMsg());
        }
        long capacity = indivSpace.getCapacity() + param.getCapacity();
        if (capacity < 0) {
            BusinessException.happen(IndivExceptionEnum.SPACE_CAPACITY_ERROR.getCode(),
                    IndivExceptionEnum.SPACE_CAPACITY_ERROR.getMsg());
        }
        indivSpace.setCapacity(capacity);
        indivSpaceDao.updateById(indivSpace);
    }

    @Override
    public List<IndivSpace> listByUser(IndivSpaceFindByUserReq param) {
        List<IndivSpaceUser> indivSpaceUsers = indivSpaceUserDao.list(
                new QueryWrapper<IndivSpaceUser>()
                        .lambda()
                        .eq(IndivSpaceUser::getUserId, param.getUserId())
        );
        Set<Long> spaceIds = indivSpaceUsers.stream().map(IndivSpaceUser::getSpaceId).collect(Collectors.toSet());
        return indivSpaceDao.listByIds(spaceIds);
    }

    @Override
    public IndivSpaceCountFileVo getCountFile(IndivSpaceCountFileReq param) {
        return null;
    }

    @Override
    public IndivSpaceCountRecordVo getCountRecord(IndivSpaceCountRecordReq param) {
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(List<Long> idList) {
        long folderCount = indivFolderDao.count(
                new LambdaQueryWrapper<IndivFolder>().in(IndivFolder::getSpaceId, idList)
        );
        if (folderCount > 0) {
            BusinessException.happen(IndivExceptionEnum.SPACE_HAVE_FOLDER.getCode(),
                    IndivExceptionEnum.SPACE_HAVE_FOLDER.getMsg());
        }
        indivSpaceDao.removeBatchByIds(idList);
        indivSpaceUserDao.remove(new LambdaQueryWrapper<IndivSpaceUser>().in(IndivSpaceUser::getSpaceId, idList));
    }
}
